const axios = require('axios');
const fs = require('fs');
const path = require('path');

/**
 * 文件下载器 - 改造版本，支持进度回调
 * 基于原有downloadBook.js改造，增加了回调机制
 */
class FileDownloader {
  constructor(downloadDirectory = null, cookie = null) {
    // 优先使用传入的参数，其次使用环境变量，最后使用默认值
    this.downloadDirectory = downloadDirectory || 
                            process.env.DOWNLOAD_DIR || 
                            path.join(__dirname, '../storage/downloads');
    
    this.cookie = cookie || 
                  process.env.ZLIB_COOKIE || 
                  `prefers_color_scheme=light; switchLanguage=en; refuseChangeDomain=1; zlib-searchView=table; remix_userkey=75f1b083eb4dd9452a015a8cc9b52ec1; remix_userid=44828022; selectedSiteMode=books; siteLanguage=zh`;
    
    this.ensureDownloadDirectory();
    console.log(`📁 下载目录: ${this.downloadDirectory}`);
    console.log(`🍪 Cookie已配置: ${this.cookie.substring(0, 50)}...`);
  }

  /**
   * 确保下载目录存在
   */
  ensureDownloadDirectory() {
    try {
      if (!fs.existsSync(this.downloadDirectory)) {
        fs.mkdirSync(this.downloadDirectory, { recursive: true });
        console.log(`📁 创建下载目录: ${this.downloadDirectory}`);
      }
    } catch (error) {
      console.error(`❌ 创建下载目录失败: ${error.message}`);
      // 如果自定义目录创建失败，回退到默认目录
      const defaultDir = path.join(__dirname, '../storage/downloads');
      console.log(`🔄 回退到默认目录: ${defaultDir}`);
      this.downloadDirectory = defaultDir;
      if (!fs.existsSync(this.downloadDirectory)) {
        fs.mkdirSync(this.downloadDirectory, { recursive: true });
      }
    }
  }

  /**
   * 获取文件名从URL或Content-Disposition头
   */
  getFileName(url, headers = {}) {
    // 尝试从Content-Disposition头获取文件名
    const contentDisposition = headers['content-disposition'];
    if (contentDisposition) {
      // 首先尝试解析 RFC 5987 格式的 filename* 参数
      const filenameStarMatch = contentDisposition.match(/filename\*\s*=\s*([^']*)'([^']*)'(.+)/);
      if (filenameStarMatch) {
        const charset = filenameStarMatch[1] || 'UTF-8';
        const encodedFilename = filenameStarMatch[3];

        try {
          // 解码 URL 编码的文件名
          const decodedFilename = decodeURIComponent(encodedFilename);
          console.log(`📄 从 filename* 解析到文件名: ${decodedFilename}`);
          return this.sanitizeFileName(decodedFilename);
        } catch (error) {
          console.log(`⚠️  filename* 解码失败: ${error.message}`);
        }
      }

      // 如果没有 filename* 参数，尝试解析普通的 filename 参数
      const filenameMatch = contentDisposition.match(/filename\s*=\s*(?:"([^"]*)"|'([^']*)'|([^;,\s]*))/);
      if (filenameMatch) {
        // 获取匹配的文件名（可能在引号内或外）
        const filename = filenameMatch[1] || filenameMatch[2] || filenameMatch[3];
        if (filename) {
          try {
            // 尝试解码可能的 URL 编码
            const decodedFilename = decodeURIComponent(filename);
            console.log(`📄 从 filename 解析到文件名: ${decodedFilename}`);
            return this.sanitizeFileName(decodedFilename);
          } catch (error) {
            // 如果解码失败，直接使用原文件名
            console.log(`📄 直接使用文件名: ${filename}`);
            return this.sanitizeFileName(filename);
          }
        }
      }
    }

    // 从URL获取文件名
    try {
      const urlObj = new URL(url);
      const pathname = urlObj.pathname;
      let filename = path.basename(pathname);

      // 如果没有文件名或者文件名太简单，使用默认名称
      if (!filename || filename === '/' || filename.length < 3) {
        const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
        filename = `download_${timestamp}`;
      }

      return this.sanitizeFileName(filename);
    } catch (error) {
      // 如果URL解析失败，使用时间戳作为文件名
      const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
      return `download_${timestamp}`;
    }
  }

  /**
   * 清理和验证文件名，确保文件系统兼容性
   */
  sanitizeFileName(filename) {
    if (!filename) {
      const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
      return `download_${timestamp}`;
    }

    // 移除或替换不安全的字符，但保留中文字符
    let sanitized = filename
      .replace(/[<>:"/\\|?*\x00-\x1f]/g, '_')  // 替换文件系统不允许的字符
      .replace(/\s+/g, ' ')  // 合并多个空格
      .trim();

    // 确保文件名不为空且不以点开头
    if (!sanitized || sanitized.startsWith('.')) {
      const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
      sanitized = `download_${timestamp}`;
    }

    // 限制文件名长度（保留扩展名）
    if (sanitized.length > 200) {
      const ext = path.extname(sanitized);
      const base = path.basename(sanitized, ext);
      sanitized = base.substring(0, 200 - ext.length) + ext;
    }

    return sanitized;
  }

  /**
   * 格式化文件大小
   */
  formatFileSize(bytes) {
    if (bytes === 0) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }

  /**
   * 获取重定向后的真实下载链接
   * @param {string} url - 初始链接
   */
  async getRealDownloadUrl(url) {
    try {
      console.log(`🔍 检查重定向: ${url}`);

      // 使用GET请求但不下载内容，只获取重定向信息
      const response = await axios({
        method: 'GET',
        url: url,
        maxRedirects: 0,
        timeout: 30000,
        headers: {
          cookie: this.cookie,
          'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36',
          'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'
        }
      });

      // 检查是否有重定向
      if (response.headers.location) {
        const redirectUrl = response.headers.location;
        console.log(`🔗 发现重定向: ${redirectUrl}`);

        // 如果是相对路径，需要组合成完整URL
        if (redirectUrl.startsWith('/')) {
          const urlObj = new URL(url);
          return `${urlObj.protocol}//${urlObj.host}${redirectUrl}`;
        } else if (redirectUrl.startsWith('http')) {
          return redirectUrl;
        } else {
          const urlObj = new URL(url);
          return `${urlObj.protocol}//${urlObj.host}/${redirectUrl}`;
        }
      }

      return url;

    } catch (error) {
      // 如果是重定向错误，尝试从错误中获取location
      if (error.response && error.response.headers && error.response.headers.location) {
        const redirectUrl = error.response.headers.location;
        console.log(`🔗 从错误响应中发现重定向: ${redirectUrl}`);

        if (redirectUrl.startsWith('http')) {
          return redirectUrl;
        } else if (redirectUrl.startsWith('/')) {
          const urlObj = new URL(url);
          return `${urlObj.protocol}//${urlObj.host}${redirectUrl}`;
        }
      }

      console.log(`⚠️  重定向检查失败，将直接尝试下载: ${error.message}`);
      return url;
    }
  }

  /**
   * 检查下载链接是否有效
   * @param {string} url - 下载链接
   */
  async checkDownloadValidity(url) {
    // 检查是否为Z-Library错误页面
    if (url.includes('wrongHash')) {
      console.log('⚠️  检测到Z-Library错误页面，可能原因：');
      console.log('   - 下载链接已过期');
      console.log('   - 需要登录Z-Library账户');
      console.log('   - 文件已被移除');
      console.log('💡 建议：请从Z-Library网站重新获取下载链接');
      return false;
    }
    return true;
  }

  /**
   * 下载文件 - 增强版本，支持进度回调
   * @param {string} url - 下载链接
   * @param {string} customFileName - 自定义文件名（可选）
   * @param {Object} callbacks - 回调函数集合
   * @param {Function} callbacks.onProgress - 进度回调 (downloaded, total, progress)
   * @param {Function} callbacks.onStart - 开始回调 (fileName, fileSize)
   * @param {Function} callbacks.onComplete - 完成回调 (result)
   * @param {Function} callbacks.onError - 错误回调 (error)
   */
  async downloadFile(url, customFileName = null, callbacks = {}) {
    const {
      onProgress = () => { },
      onStart = () => { },
      onComplete = () => { },
      onError = () => { }
    } = callbacks;

    try {
      console.log(`🚀 开始下载流程: ${url}`);

      // 首先获取真实的下载链接
      const realUrl = await this.getRealDownloadUrl(url);
      console.log(`📥 准备下载文件: ${realUrl}`);

      // 检查下载链接有效性
      if (!await this.checkDownloadValidity(realUrl)) {
        const error = new Error('下载链接无效或已过期');
        onError(error);
        throw error;
      }

      // 创建HTTP请求配置
      const config = {
        method: 'GET',
        url: realUrl,
        responseType: 'stream',
        timeout: 60000, // 60秒超时
        maxRedirects: 10, // 允许重定向
        headers: {
          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
        }
      };

      // 发送请求
      const response = await axios(config);

      // 获取文件名
      const fileName = customFileName || this.getFileName(realUrl, response.headers);
      const filePath = path.join(this.downloadDirectory, fileName);

      // 获取文件大小
      const totalSize = parseInt(response.headers['content-length'] || '0');
      let downloadedSize = 0;

      console.log(`📄 文件名: ${fileName}`);
      if (totalSize > 0) {
        console.log(`📊 文件大小: ${this.formatFileSize(totalSize)}`);
      }
      console.log(`💾 保存路径: ${filePath}`);

      // 触发开始回调
      onStart(fileName, totalSize);

      // 创建写入流
      const writer = fs.createWriteStream(filePath);

      // 监听下载进度
      response.data.on('data', (chunk) => {
        downloadedSize += chunk.length;
        const progress = totalSize > 0 ? ((downloadedSize / totalSize) * 100) : 0;

        // 触发进度回调
        onProgress(downloadedSize, totalSize, progress);

        if (totalSize > 0) {
          process.stdout.write(`\r⏳ 下载进度: ${progress.toFixed(2)}% (${this.formatFileSize(downloadedSize)}/${this.formatFileSize(totalSize)})`);
        } else {
          process.stdout.write(`\r⏳ 已下载: ${this.formatFileSize(downloadedSize)}`);
        }
      });

      // 处理下载完成
      return new Promise((resolve, reject) => {
        response.data.pipe(writer);

        writer.on('finish', () => {
          console.log(`\n✅ 下载完成: ${fileName}`);
          console.log(`📍 文件位置: ${filePath}`);

          const result = {
            success: true,
            fileName,
            filePath,
            fileSize: downloadedSize
          };

          // 触发完成回调
          onComplete(result);
          resolve(result);
        });

        writer.on('error', (error) => {
          console.error(`\n❌ 写入文件失败:`, error.message);
          // 清理损坏的文件
          if (fs.existsSync(filePath)) {
            fs.unlinkSync(filePath);
          }
          onError(error);
          reject(error);
        });

        response.data.on('error', (error) => {
          console.error(`\n❌ 下载数据流错误:`, error.message);
          writer.destroy();
          // 清理损坏的文件
          if (fs.existsSync(filePath)) {
            fs.unlinkSync(filePath);
          }
          onError(error);
          reject(error);
        });
      });

    } catch (error) {
      console.error(`\n❌ 下载失败:`, error.message);

      if (error.response) {
        console.error(`📊 HTTP状态码: ${error.response.status}`);
        console.error(`📄 响应头:`, error.response.headers);
      }

      onError(error);
      throw error;
    }
  }
}

module.exports = FileDownloader;
